package com.atguigu.lease.web.admin.service.impl;

import com.atguigu.lease.common.minio.MinioProperties;
import com.atguigu.lease.web.admin.service.FileService;
import io.minio.*;
import io.minio.errors.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private MinioClient minioClient;
    @Autowired
    private MinioProperties properties;


    @Override
    public String upload(MultipartFile file) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {


            //先判断提交的存放数据的存储桶是否存在
            boolean bucketExists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(
                    properties.getBucketName()).build());
            //如果不存在则创建存储桶
            if (!bucketExists) {
                minioClient.makeBucket(
                        MakeBucketArgs.builder()
                                .bucket(properties.getBucketName())
                                .build());

           //配置桶的访问权限和读取权限 默认创建是创造者
                minioClient.setBucketPolicy(SetBucketPolicyArgs.builder()
                        .bucket(properties.getBucketName())
                        .config(createBucketPolicyConfig(properties.getBucketName()))
                        .build());

            }
            //为了防止上传同名文件被覆盖 这里设置上传文件的文件名  时间/uuid+文件原始命
            //对象名 20231015/3b9d7f2a-abc.jpg 会被视为：
            //位于虚拟目录 20231015 下的文件 3b9d7f2a-abc.jpg
            //在 MinIO 控制台或客户端中，会自动按 / 分割显示为目录树结构。
            String filename=new SimpleDateFormat("yyyyMMdd").format(new Date())+
                    "/"+ UUID.randomUUID()+"-"+file.getOriginalFilename();
            //最后上传文件
            minioClient.putObject(PutObjectArgs.builder()
                    //上传的路径用户名密码都已经在配置文件映射到properties实体类里了
                    //上传的桶名
                    .bucket(properties.getBucketName())
                    //上传文件以流的形式上传 1用于读取上传文件的二进制数据 2上传文件的大小  3是分块发送的快大小 这里-1是minio自动设置分片大小发送
                    .stream(file.getInputStream(),file.getSize(),-1)
                    //上传后给文件起个文件名
                    .object(filename)
                    //默认上传后的请求头不是image....而是application/什么什么
                    // 如果请求头是appplication什么什么我们访问照片时会自动下载 我们要的效果是直接在浏览器展示
                    //这里就设置了文件是什么类型 请求头就是什么类型
                    .contentType(file.getContentType())
                    .build());
                //返回访问的url路径  服务器地址+桶名+文件名 “/”拼接后面的数据即 服务器地址/桶名/文件名

            return String.join("/",properties.getEndpoint(),properties.getBucketName(),filename);




    }

    //设置访问权限并返回 return String.join("/",properties.getEndpoint(),properties.getBucketName(),);
    private String createBucketPolicyConfig(String bucketName) {
        return """
                {
                  "Statement" : [ {
                    "Action" : "s3:GetObject",
                    "Effect" : "Allow",
                    "Principal" : "*",
                    "Resource" : "arn:aws:s3:::%s/*"
                  } ],
                  "Version" : "2012-10-17"
                }
                """.formatted(bucketName);
        //formatted(bucketName)是挺好%s占位符

    }
}
